//Внутренняя библиотека.
#include "motion.h"
#include "vidframe.h"


//===========================================================================//
//=Заголовок: Motion::Motion() - public
//=Параметры:
//=Описание: Конструктор.
//===========================================================================//
Motion::Motion(int index, QObject *parent) : VidFilter(index, parent)
{
isTest = false;
image = NULL; lastImage = NULL; diffImage = NULL;
treshold = 30; sensitive = 10; length = 0;
adaptiveTreshold = false; noiseRemoving = false;
vData = NULL; width = 0; height = 0; len = 0;
storage = cvCreateMemStorage(0);
contour = NULL;
}


//===========================================================================//
//=Заголовок: Motion::~Motion() - public
//=Параметры:
//=Описание: Деструктор.
//===========================================================================//
Motion::~Motion()
{
if(storage) cvReleaseMemStorage(&storage);
if(vData) delete[] vData;
if(image) cvReleaseImage(&image);
if(lastImage) cvReleaseImage(&lastImage);
if(diffImage) cvReleaseImage(&diffImage);
}


//===========================================================================//
//=Заголовок: void Motion::setTestMode() - public
//=Параметры:
//=Описание: Функция управления режимом тестирования ДД.
//===========================================================================//
void Motion::setTestMode(bool testmode) {isTest = testmode;}


//===========================================================================//
//=Заголовок: void Motion::isTestMode() - public
//=Параметры:
//=Описание: Функция определения активности режима тестирования ДД.
//===========================================================================//
bool Motion::isTestMode() {return isTest;}


//===========================================================================//
//=Заголовок: void Motion::setTreshold() - public
//=Параметры:
//=Описание: Функция установки порога срабатывания ДД.
//===========================================================================//
void Motion::setTreshold(int _treshold)
{
if(_treshold == 0) adaptiveTreshold = true;
else {treshold = _treshold; adaptiveTreshold = false;}
}


//===========================================================================//
//=Заголовок: int Motion::getTreshold() - public
//=Параметры:
//=Описание: Функция возврата порога срабатывания ДД.
//===========================================================================//
int Motion::getTreshold() {return treshold;}


//===========================================================================//
//=Заголовок: void Motion::setSensitive() - public
//=Параметры:
//=Описание: Функция установки чувствительности ДД.
//===========================================================================//
void Motion::setSensitive(int _sensitive) {sensitive = _sensitive;}


//===========================================================================//
//=Заголовок: int Motion::getSensitive() - public
//=Параметры:
//=Описание: Функция возврата чувствительности ДД.
//===========================================================================//
int Motion::getSensitive() {return sensitive;}


//===========================================================================//
//=Заголовок: void Motion::setNoiseRemoving() - public
//=Параметры:
//=Описание: Функция установки подавления шума.
//===========================================================================//
void Motion::setNoiseRemoving(bool noise_remove) {noiseRemoving = noise_remove;}


//===========================================================================//
//=Заголовок: bool Motion::getNoiseRemoving() - public
//=Параметры:
//=Описание: Функция возврата состояния параметра подавления шума.
//===========================================================================//
bool Motion::getNoiseRemoving() {return noiseRemoving;}


//===========================================================================//
//=Заголовок: void Motion::detect() - public
//=Параметры:
//=Описание: Функция активации ДД.
//===========================================================================//
void Motion::detect(VidFrame *vidframe)
{
len = vidframe->getLength();
if(len != length && vData) {delete[] vData; vData = NULL;}
if(!vData)
	{
	width = vidframe->getWidth();
	height = vidframe->getHeight();
	vData = new uchar[len];
}
memcpy(vData, vidframe->getData(), len);

if(len != length)
	{
	if(image) cvReleaseImage(&image);
	image = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
	image->imageData = (char*)vData;
	//cvErode(image, image, NULL, 1);
	//cvDilate(image, image, NULL, 1);
	if(noiseRemoving) cvSmooth(image, image, CV_BLUR, 3, 3);
	else cvSmooth(image, image, CV_BLUR, 1, 1);

	if(lastImage) cvReleaseImage(&lastImage);
	lastImage = cvCloneImage(image);

	if(diffImage) cvReleaseImage(&diffImage);
	diffImage = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);

	length = len;
	return;
}

image->imageData = (char*)vData;
//cvErode(image, image, NULL, 1);
//cvDilate(image, image, NULL, 1);
if(noiseRemoving) cvSmooth(image, image, CV_BLUR, 3, 3);
else cvSmooth(image, image, CV_BLUR, 1, 1);
cvAbsDiff(image, lastImage, diffImage);

if(adaptiveTreshold)
	cvAdaptiveThreshold(diffImage, diffImage, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV);
else cvThreshold(diffImage, diffImage, treshold, 255, CV_THRESH_BINARY);

cvReleaseImage(&lastImage);
lastImage = cvCloneImage(image);

cvClearMemStorage(storage);
int points = cvFindContours(diffImage, storage, &contour, sizeof(CvContour));

switch(isTest)
	{
	case false:
		if(points > sensitive) {length = 0; emit motionDetect();}
	break;
	case true:
		if(points > sensitive) emit achievedTreshold(true);
		else emit achievedTreshold(false);
	break;
}
}


//===========================================================================//
//=Заголовок: void Motion::drawDetection() - public
//=Параметры:
//=Описание: Функция рисования точек движения.
//===========================================================================//
void Motion::drawDetection(IplImage *img)
{
/*for (; contour != 0; contour = contour->h_next)
	{
		rect = cvBoundingRect(contour, 1);
		if (	(rect.width + rect.height > 5) && !(
				//((rect.height / rect.width) < 1.1) &&
				((rect.width / rect.height) < 1.1)))
		{
			cvDrawContours(src_contours, contour, CV_RGB(2, 198, 255), CV_RGB(2, 198, 255), -1, CV_FILLED, 8);
			// Bound cone by green square
			cvRectangle(src, cvPoint(rect.x, rect.y), cvPoint(rect.x
					+ rect.width, rect.y + rect.height), CV_RGB(255, 0, 0), 5);
		}
	}*/

if(!img) return;
while(contour)
	{
	CvScalar color = CV_RGB(255, 255, 255);
	cvDrawContours(img, contour, color, color, 0, 1, CV_AA);
	contour = contour->h_next;
}
}
